package com.zsy.swagger.config;

import cn.hutool.core.util.StrUtil;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.Arrays;
import java.util.Collections;

/**
 * @program: my-springcloud
 * @description: swagger配置
 * @author: zhaoshouyun
 * @create: 2020-04-21 15:00
 **/
@Configuration
@Profile({ "dev","test"})
@EnableKnife4j//启用增强注解
public class Swagger2Configuration {
    //需要再启动主类添加@EnableSwagger2

    // 定义分隔符
    private static final String SPLITOR = ";";

    private static StringBuilder basePackages= new StringBuilder();

    @Value("${spring.application.name}")
    String springApplicationName;
    /**
     * 此处初始化多包扫描，其他地方不用修改；除非你确定你在改什么
     **/
    static {
        //oauth2对外的接口服务
        basePackages.append("com.zsy.oauth2.controller").append(SPLITOR);
        //demo 对外的接口
        basePackages.append("com.zsy.provider.controller").append(SPLITOR);
        //provider-uac 对外的接口
        basePackages.append("com.zsy.provider.web");

    }

    //String AUTH_SERVER = "http://localhost:7000/api"; 网关
    String AUTH_SERVER = "http://localhost:8005";
    //String AUTH_SERVER = "http://localhost:8001";

    /**
     * @Description 创建api
     * @Author zhaoshouyun
     * @Date 18:25 2020/4/23
     * @Param []
     * @return springfox.documentation.spring.web.plugins.Docket
     **/
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //.apis(RequestHandlerSelectors.basePackage("com.zsy.oauth2.controller"))
                //支持多包扫描
                .apis(scanBasePackage(basePackages.toString()))
                .paths(PathSelectors.any())
                .build()
                //.ignoredParameterTypes(HttpSession.class) //添加忽略类型
                .securitySchemes(Collections.singletonList(securityScheme()))
                .securityContexts(Collections.singletonList(securityContext()));
    }

    /**
     * @Description 设置swagger相关配置
     * @Author zhaoshouyun
     * @Date 18:24 2020/4/23
     * @Param []
     * @return springfox.documentation.service.ApiInfo
     **/
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(springApplicationName + " API 文档")
                .description(springApplicationName + " API 接口，https://www.yunfeng.org.cn")
                .termsOfServiceUrl("https://www.yunfeng.org.cn")
                .contact(new Contact("zhaoshouyun","https://www.yunfeng.org.cn","1065609785@qq.com"))
                .version("1.0.0")
                .build();
    }


    /**
     * 这个类决定了你使用哪种认证方式，我这里使用密码模式
     * @author zhaoshouyun
     */
    private SecurityScheme securityScheme() {
        GrantType grantType = new ResourceOwnerPasswordCredentialsGrant(AUTH_SERVER + "/oauth/token");

        return new OAuthBuilder()
                .name("spring_oauth")
                .grantTypes(Collections.singletonList(grantType))
                .scopes(Arrays.asList(scopes()))
                .build();
    }

    /**
     * 这里设置 swagger2 认证的安全上下文
     * @author zhaoshouyun
     */
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(Collections.singletonList(new SecurityReference("spring_oauth", scopes())))
                .forPaths(PathSelectors.any())
                .build();
    }

    /**
     * 这里是写允许认证的scope
     * @author zhaoshouyun
     */
    private AuthorizationScope[] scopes() {
        return new AuthorizationScope[]{
                new AuthorizationScope("all", "All scope is trusted!")
        };
    }

    /**
     * 切割扫描的包生成Predicate<RequestHandler>
     * @author zhaoshouyun
     * @param basePackage
     * @return
     */
    public static Predicate<RequestHandler> scanBasePackage(final String basePackage) {
        if(StrUtil.isBlank(basePackage)){
            throw new NullPointerException("basePackage不能为空，多个包扫描使用"+SPLITOR+"分隔");
        }
        String[] controllerPack = basePackage.split(SPLITOR);
        Predicate<RequestHandler> predicate = null;
        for (int i = controllerPack.length -1; i >= 0 ; i--) {
            String strBasePackage = controllerPack[i];
            if(StrUtil.isNotBlank(strBasePackage)){
                Predicate<RequestHandler> tempPredicate = RequestHandlerSelectors.basePackage(strBasePackage);
                predicate = predicate == null ? tempPredicate : Predicates.or(tempPredicate,predicate);
            }
        }
        if(predicate == null){
            throw new NullPointerException("basePackage配置不正确，多个包扫描使用"+SPLITOR+"分隔");
        }
        return predicate;
    }
}
